package com.yangqun.main;

import com.alibaba.fastjson.JSONObject;
import com.yangqun.util.ReflexUtil;
import org.apache.poi.ss.usermodel.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author YangTao 2018年6月15日14:43:55
 * 用于读取Excel 转换为实体，只需实体实现方法和加上注解，
 * 注解的和Excel和属性对应，如Excel有一列 姓名
 *                                    aa
 *                                    bbb
 *  实体有一个属性 name 我们想把name和姓名对应起来
 *  则我们在实体代码中加入如下代码：
 *  @ExcelBeanMethodUtil(excelHeadName="姓名",excelHeadMthod="name")
 *  最新版修改为 @ExcelBeanMethodUtil(excelHeadName="姓名",attributeName="name") 这样不和导出混淆
    public String name;
    其他类似。
 *  工具会自动将Excel中的值转为实体上的值。
 *  最后以列表实体方式返回。
 *  该工具类不在提供接口，实现对数据正确性和错误性进行校验，提供了就不符合单一职责原则。
 *  使用方法：
 *  List<Studer> list =  execlRead.readRowExcelContent(is,Studer.class,0,0,null);
 *  具体参数可以看方法说明。
 */
public class ImportExcelUtil<T> {

	private  Map<String,String> headMethodName = new HashMap<String,String>();

	private Workbook wb;

	public  InputStream readFileAsStream(String path) throws IOException{
		if(path == null){
			return null;
		}else{
			File file = new File(path);
			return readFileAsStream(file);
		}
	}
	
	public  InputStream readFileAsStream(File file) throws IOException{
		if(!file.exists()){
			return null;
		}
		if(file.isFile() && file.canRead()){
			return new FileInputStream(file);
		}else{
			return null;
		}
	}
	/**
	 * main 方法用于测试，和演示使用
	 * @author YangTao 2016年1月31日 上午11:49:24
	 * @return void
	 */
//	public static void main(String[] args) {
//		ExeclReadUtilAnnotation execlRead = new ExeclReadUtilAnnotation();
//		InputStream is;
//		try {
//			//实体类，演示用法
//			//Persion persion = new Persion();
////			EduMasterdataMarkeinfoDO eduMasterdataMarkeinfoDO = new EduMasterdataMarkeinfoDO();
//			//默认处理Execlhandle 演示使用
////			DefaultHandleExecl defaultHandleExecl = new DefaultHandleExecl();
//			is = execlRead.readFileAsStream("E:/student.xls");
//			if(is == null){
//				return;
//			}
////			int number = execlRead.getStartPos(is, "序号");
////			System.out.println(number);
////			Out_Parameter_Total out_Parameter_Total = new Out_Parameter_Total(0);
////			execlRead.readDate(is, eduMasterdataMarkeinfoDO, defaultHandleExecl, ColORRow.ROW, 0, out_Parameter_Total);
//
//			List<Studer> list =  execlRead.readRowExcelContent(is,Studer.class,0,0,null);
//
//			for(Studer studer : list){
//				System.out.println(studer.toString());
//			}
//
//		}  catch (IOException e) {
//			e.printStackTrace();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//
//	}

    /**
     *
     * @param is 输入流
     * @param excelExportMustImpMethodBeanClass 传入将Excel要转换成的实体类.class 如Student.class 该类需实现@see ExcelExportMustImpMethodBean接口。
     * @param startPos 开始位置，可由原ExcelReadUtill提供，该方法暂时为移动到ExcelUtil中，因为有部分应用已经在使用了。如无特殊指定，传入 0 就可以了。
     * @param rows 读取多少数据，传入0 表示读取从开始位置读取到文件末。
     * @param sheetName 指定读取哪个sheet
     * @param <T> 类型
     * @return
     * @throws Exception
     */
    public <T> List<T> readRowExcelContent(InputStream is,Class<T> excelExportMustImpMethodBeanClass,int startPos,int rows,String sheetName) throws Exception {

    	List<T> returnList = new LinkedList<T>();

    	List<String> excelTitle = new ArrayList<String>();

		wb = WorkbookFactory.create(is);
		Sheet sheet  = null;
		if(sheetName == null){
			sheet =  wb.getSheetAt(0);
		}else{
			sheet =  wb.getSheet(sheetName);
		}

		if(sheet == null){
			return returnList;
		}
        // 得到总行数 用于计算需要读取的位置
        int rowNum = sheet.getLastRowNum();
        Row row = sheet.getRow(startPos);
        int colNum = row.getPhysicalNumberOfCells();
        //获取Execl标题
    	for(int i = 0 ; i < colNum; i++){
    		if(row.getCell(i) == null){
    			colNum++;
				excelTitle.add("");
    			continue;
    		}
			excelTitle.add(row.getCell(i).getStringCellValue());
    	}
		//传入0的话，表示全部读取。
    	if(rows == 0){
    	}else{
			//即 从开始位置 + 要读取的行数。
    		 rowNum = startPos + rows;
    	}
    	
    	startPos++;
    	
        for (;startPos <= rowNum; startPos++) {
        	
            row = sheet.getRow(startPos);

			StringBuilder sb = new StringBuilder("{");

            for(int cellPos = 0; cellPos < colNum; cellPos++){

            	String excelTileBeanName = excelTitle.get(cellPos);


				if(excelTileBeanName == null || excelTileBeanName.equals("")){
					continue;
				}
				String attributeName =  headMethodName.get(excelTileBeanName);

				if(attributeName == null){
					attributeName = ReflexUtil.getAttributeName(excelExportMustImpMethodBeanClass.getFields(),excelTileBeanName);
					headMethodName.put(excelTileBeanName,attributeName);
				}
				if(attributeName == null || attributeName.equals("")){
					continue;
				}

				sb.append(attributeName).append(":").append(getCellFormatValue(row.getCell(cellPos))).append(",");

            }
			System.out.println(sb.toString());
			sb.deleteCharAt(sb.length() - 1).append("}");

			T t = JSONObject.parseObject(sb.toString(),excelExportMustImpMethodBeanClass);

			returnList.add(t);
        }
        return returnList;
    }


	/**
	 * 转换Execl中的值
	 * @author YangTao 2016-3-7 下午1:20:59
	 * @param cell
	 * @return String
	 */
	public static String getCellFormatValue(Cell cell) {
		String cellvalue = "";
		if (cell != null) {
			switch (cell.getCellType()) {
				case STRING:
					// 取得当前的Cell字符串 由于我们转成字符JSON形式的字符串，我们在字符串上面加上引号
					cellvalue = "\"" + cell.getRichStringCellValue().getString().replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\\\\\"") + "\"";

					break;
				case BLANK:
					cellvalue = "\"\"";
					break;
				case NUMERIC:
					if (DateUtil.isCellDateFormatted(cell)) {
						Date date = cell.getDateCellValue();
						SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
						cellvalue =  "\"" + sdf.format(date) + "\"";
					}else{
						//YangTao 2018年6月11日17:11:32 将带小数点的数字 用String类型读取，避免POI将数字转成Double型 多很多000000
//					cell.setCellType(Cell.CELL_TYPE_STRING);
						DecimalFormat df = new DecimalFormat("0.00#####");

						BigDecimal bigDecimal = new BigDecimal(String.valueOf(cell.getNumericCellValue()));
						cellvalue = df.format(bigDecimal);
					}
					break;

				case FORMULA: {
					// 判断当前的cell是否为Date
					if (DateUtil.isCellDateFormatted(cell)) {
						// 如果是Date类型则，转化为Data格式

						//方法1：这样子的data格式是带时分秒的：2011-10-12 0:00:00
						//cellvalue = cell.getDateCellValue().toLocaleString();

						//方法2：这样子的data格式是不带带时分秒的：2011-10-12
						Date date = cell.getDateCellValue();
						SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
						cellvalue = "\"" + sdf.format(date) + "\"";
					}
					// 如果是纯数字
					else {
						// 取得当前Cell的数值
						DecimalFormat df = new DecimalFormat("0.00");

						cellvalue = df.format(cell.getNumericCellValue());
					}
					break;
				}

				// 默认的Cell值
				default:
					cellvalue = "\"\"";
			}
		} else {
			cellvalue = "\"\"";
		}
		return cellvalue;

	}


}
